package com.spot.data.test.demo.biz;

import com.spot.data.test.demo.dto.*;
import com.spot.data.test.demo.mapper.CashPoolMapper;
import com.spot.data.test.demo.mapper.ComExpiryMapper;
import com.spot.data.test.demo.mapper.ComMapper;
import com.spot.data.test.demo.mapper.PledgeMapper;
import com.spot.data.test.demo.util.DateUtil;
import com.spot.data.test.demo.vo.CommonsSearchVo;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.math.NumberUtils;
import org.apache.commons.lang.time.DateUtils;
import org.joda.time.DateTime;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.math.BigDecimal;
import java.util.*;

/**
 * <p></p>
 *
 * @author Andy
 * @date 2020/6/2
 * @since 1.2
 */
@Component
public class ComBiz {
    @Autowired
    private ComMapper comMapper;

    @Autowired
    private PledgeMapper pledgeMapper;

    @Autowired
    private ComExpiryMapper comExpiryMapper;

    @Autowired
    private CashPoolMapper cashPoolMapper;

    public void generateComExpiry() {
        Collection<ComDto> comDtos = comMapper.selectAll();
        CommonsSearchVo searchVo = new CommonsSearchVo();

        DateTime dateTime = new DateTime("2022-10-30");
        Date date = new Date();
        int cnt = 0;
        boolean isQuote;
        for (; ; ) {
            // 程序的执行日期
            DateTime executeDate = new DateTime(DateUtils.addDays(dateTime.toDate(), cnt));
            int compare = DateUtils.truncatedCompareTo(executeDate.toDate(), date, Calendar.DATE);
            if (compare >= 0) break;

            // 当前的日期 yyyy-MM-dd
            Date queryDate = executeDate.millisOfDay().withMaximumValue().toDate();
            searchVo.setDeadlineTime(queryDate);
           /* ComDto dto = new ComDto();
            dto.setUcId("26a49cff00001194");*/
            for (ComDto dto : comDtos) {
                searchVo.setUcId(dto.getUcId());
                searchVo.setBeginDate(null);
                searchVo.setEndDate(null);
                //查看当天是否有挂单的数据
                isQuote = doGenerateQuoteComExpiry(searchVo, dto, executeDate);
                if (!isQuote) {
                    searchVo.setBeginDate(null);
                    searchVo.setEndDate(null);
                    searchVo.setDeadlineTime(null);
                    doGenerateRenewComExpiry(searchVo, dto, executeDate);
                }
            }
            cnt++;
        }
    }


    /**
     * 递归调用查找原始的续期仓单
     *
     * @param pledge
     * @param currentDate
     * @param firstAndLastNumberMaps
     * @return
     */
    private boolean invokeRecursion(CommonsSearchVo searchVo, ComDto dto, PledgeDto pledge,
                                    DateTime currentDate, Map<String, PledgeDto> firstAndLastNumberMaps) {
        if (Objects.nonNull(pledge.getRenewPledgeId())) {
            PledgeDto parentPledge = pledgeMapper.get(pledge.getRenewPledgeId());
            // 判断是否是最源始的续期仓单
            if (Objects.isNull(parentPledge.getRenewPledgeId())) {
                firstAndLastNumberMaps.put("parentNumber", parentPledge);
            }

            // 判断是否是同一个仓单
            if (Objects.nonNull(parentPledge)) {
                if (Objects.nonNull(parentPledge.getRenewPledgeId())
                        && StringUtils.equalsIgnoreCase(pledge.getNumber(), parentPledge.getNumber())) {
                    invokeRecursion(searchVo, dto, parentPledge, currentDate, firstAndLastNumberMaps);
                }

                if (StringUtils.equalsIgnoreCase(pledge.getNumber(), parentPledge.getNumber())) {
                    return getRenewExpiryCount(searchVo, dto, firstAndLastNumberMaps, currentDate);
                }
            }
        }
        return Boolean.FALSE;
    }

    /**
     * 处理没有续期或最初始的续期仓单
     *
     * @param searchVo    电商会员逾期或挂单的搜索vo
     * @param pledge      获取挂单的搜索vo
     * @param dto         当前电商会员
     * @param currentDate 当前的发生日期
     * @return 如果有逾期的那么返回true，否则false
     */
    private boolean noneRenewBiz(CommonsSearchVo searchVo, PledgeDto pledge, ComDto dto, DateTime currentDate) {
        int compare;
        // 判断代理状态还在进行中，这个算逾期处理
        if (pledge.getStatus() == 2) {
            // 进行中
            if (Objects.isNull(pledge.getFinishTime())) {
                return doNoneRenewCheckAndSave(searchVo, dto, currentDate);
            }

            // 防止错误数据，正常的话，不会出现此种情况
            compare = DateUtils.truncatedCompareTo(currentDate.toDate(),
                    pledge.getFinishTime(), Calendar.DATE);
            if (compare < NumberUtils.INTEGER_ZERO) {
                return doNoneRenewCheckAndSave(searchVo, dto, currentDate);
            }
        }

        compare = DateUtils.truncatedCompareTo(pledge.getDeadlineTime(),
                currentDate.toDate(), Calendar.DATE);
        if (compare < NumberUtils.INTEGER_ZERO) {
            if (pledge.getStatus() == 4) {
                // 判断当前仓单的了结日期是否小于等于当前日期，如果小于等于，那么它算逾期
                compare = DateUtils.truncatedCompareTo(currentDate.toDate(),
                        pledge.getFinishTime(), Calendar.DATE);
                if (compare < NumberUtils.INTEGER_ZERO) {
                    return doNoneRenewCheckAndSave(searchVo, dto, currentDate);
                }
            }
        }
        return Boolean.FALSE;
    }

    /**
     * 获取逾期的次数
     *
     * @param firstAndLastNumberMaps
     * @param currentDate
     * @return
     */
    private boolean getRenewExpiryCount(CommonsSearchVo searchVo, ComDto dto,
                                        Map<String, PledgeDto> firstAndLastNumberMaps, DateTime currentDate) {
        PledgeDto parentPledge = firstAndLastNumberMaps.get("parentNumber");
        PledgeDto childPledge = firstAndLastNumberMaps.get("childNumber");
        // 判断最原始的仓单过期日期是否小于currentDate
        int compare = DateUtils.truncatedCompareTo(parentPledge.getDeadlineTime(), currentDate.toDate(), Calendar.DATE);
        if (compare >= NumberUtils.INTEGER_ZERO) {
            return Boolean.FALSE;
        }

        CommonsSearchVo childSearch = new CommonsSearchVo();
        childSearch.setUcId(searchVo.getUcId());
        // 判断代理状态在进行中，并且还没有了结，源始仓单的过期时间小于当前时间，这个算逾期处理
        if (childPledge.getStatus() == 2) {
            if (checkIsExits(childSearch, currentDate)) return Boolean.FALSE;
            saveRenewComExpiry(childSearch, dto, currentDate, NumberUtils.INTEGER_ONE, NumberUtils.INTEGER_ZERO);
            return Boolean.TRUE;
        }

        if (childPledge.getStatus() == 4) {
            // 判断当前仓单的了结日期是否小于等于当前日期，如果小于等于，那么它算逾期
            compare = DateUtils.truncatedCompareTo(currentDate.toDate(), childPledge.getFinishTime(), Calendar.DATE);
            if (compare < NumberUtils.INTEGER_ONE) {
                int days = DateUtil.daysBetween(parentPledge.getDeadlineTime(), childPledge.getFinishTime());

                boolean isSucceed = Boolean.FALSE;
                for (int i = days - NumberUtils.INTEGER_ONE; i >= NumberUtils.INTEGER_ZERO; i--) {
                    DateTime loopDate = new DateTime(DateUtils.addDays(currentDate.toDate(), -i));
                    childSearch.setBeginDate(loopDate.millisOfDay().withMinimumValue().toDate());
                    childSearch.setEndDate(loopDate.millisOfDay().withMaximumValue().toDate());
                    long count = comExpiryMapper.count(childSearch);
                    if (count > NumberUtils.INTEGER_ZERO) continue;

                    saveRenewComExpiry(childSearch, dto, loopDate, NumberUtils.INTEGER_ONE, NumberUtils.INTEGER_ZERO);
                    isSucceed = Boolean.TRUE;
                }
                return isSucceed;
            }
        }

        return Boolean.FALSE;
    }

    /**
     * 获取逾期的次数
     *
     * @param searchVo
     * @param dto
     * @param origPledge       原始
     * @param childRenewPledge 最后一笔的续期仓单
     * @param currentDate
     * @return
     */
    private boolean getRenewExpiryCount(CommonsSearchVo searchVo, ComDto dto, PledgeDto origPledge,
                                        PledgeDto childRenewPledge, DateTime currentDate) {
        if (Objects.nonNull(origPledge.getDeadlineTime())) {
            // 判断最原始的仓单过期日期是否小于currentDate
            int compare = DateUtils.truncatedCompareTo(origPledge.getDeadlineTime(),
                    currentDate.toDate(), Calendar.DATE);
            if (compare >= NumberUtils.INTEGER_ZERO) {
                return Boolean.FALSE;
            }

            // 判断代理状态在进行中，并且还没有了结，源始仓单的过期时间小于当前时间，这个算逾期处理
            if (childRenewPledge.getStatus() == 2) {
                saveRenewOrQuote(searchVo, dto, childRenewPledge, currentDate);
                return Boolean.TRUE;
            }

            if (childRenewPledge.getStatus() == 4) {
                // 判断当前仓单的了结日期是否小于等于当前日期，如果小于等于，那么它算逾期
                compare = DateUtils.truncatedCompareTo(currentDate.toDate(),
                        childRenewPledge.getFinishTime(), Calendar.DATE);
                if (compare < NumberUtils.INTEGER_ONE) {
                    saveRenewOrQuote(searchVo, dto, childRenewPledge, currentDate);
                    return Boolean.TRUE;
                }
            }
        }

        return Boolean.FALSE;
    }

    private void saveRenewOrQuote(CommonsSearchVo searchVo, ComDto dto, PledgeDto childRenewPledge,
                                  DateTime currentDate) {
        int compare = DateUtils.truncatedCompareTo(currentDate.toDate(),
                childRenewPledge.getDeadlineTime(), Calendar.DATE);
        if (compare < NumberUtils.INTEGER_ONE) {
            saveRenewComExpiry(searchVo, dto, currentDate,
                    NumberUtils.INTEGER_ONE, NumberUtils.INTEGER_ZERO);
        } else {
            saveRenewComExpiry(searchVo, dto, currentDate,
                    NumberUtils.INTEGER_ONE, NumberUtils.INTEGER_ONE);
        }
    }

    /**
     * 是否有挂单的数据
     *
     * @param searchVo    电商会员逾期或挂单的搜索vo
     * @param dto         当前电商会员
     * @param executeDate 当前的发生日期
     * @return 如果有挂单业务发生，那么返回true，否则返回false
     */
    private boolean doGenerateQuoteComExpiry(CommonsSearchVo searchVo, ComDto dto, DateTime executeDate) {
        boolean isQuote = false;
        // 统计当天是否有挂单
        Collection<PledgeDto> pledgeList = pledgeMapper.selectQuote(searchVo);
        if (CollectionUtils.isNotEmpty(pledgeList)) {
            Date years = DateUtils.addYears(executeDate.toDate(), NumberUtils.INTEGER_MINUS_ONE);
            List<CashPoolDto> cashPoolDtos = cashPoolMapper.selectLimitTwo();
            // 当天的结算日期
            CashPoolDto cashPoolDto = cashPoolDtos.get(1);
            for (PledgeDto pledge : pledgeList) {
                // 当前日期与过期日期进行比较，如果已经过期了，再比较了结日期
                if (Objects.isNull(pledge.getDeadlineTime())) continue;
                int cashCompare = DateUtils.truncatedCompareTo(pledge.getDeadlineTime(),
                        DateTime.parse(cashPoolDto.getCashDate()).toDate(), Calendar.DATE);

                if (cashCompare > 0) {
                    // 到期日当天不为结算日，该笔数据当天不算挂单（逾期），顺延到下个到期日判断
                    isQuote = Boolean.TRUE;
                } else if (cashCompare == 0 && pledge.getStatus() == 4) {
                    // 到期日当天为结算日，该笔数据已了结，当天不算挂单（逾期）
                    isQuote = Boolean.TRUE;
                } else {
                    int compare = DateUtils.truncatedCompareTo(pledge.getDeadlineTime(),
                            executeDate.toDate(), Calendar.DATE);
                    if (compare < NumberUtils.INTEGER_ONE) {
                        // 有了结日期的挂单数据
                        if (Objects.nonNull(pledge.getFinishTime())) {
                            // 如果当前日期比了结日期还小的话，那么这笔就是挂单
                            compare = DateUtils.truncatedCompareTo(executeDate.toDate(),
                                    pledge.getFinishTime(), Calendar.DATE);
                            if (compare < NumberUtils.INTEGER_ONE) {
                                // 生成电商贸易会员逾期统计报表
                                ComExpiryDto model = createComExpiryDto(searchVo, dto, NumberUtils.INTEGER_ONE,
                                        NumberUtils.INTEGER_ONE, executeDate, years);
                                comExpiryMapper.save(model);
                                return Boolean.TRUE;
                            }
                        } else {
                            // 生成电商贸易会员逾期统计报表
                            ComExpiryDto model = createComExpiryDto(searchVo, dto, NumberUtils.INTEGER_ONE,
                                    NumberUtils.INTEGER_ONE, executeDate, years);
                            comExpiryMapper.save(model);
                            return Boolean.TRUE;
                        }
                    }
                }
            }

            // 判断当前是否有挂单数据
            if (isQuote) {
                saveRenewComExpiry(searchVo, dto, executeDate, 0, 0);
                return Boolean.TRUE;
            }
        }
        return false;
    }

    /**
     * 是否有逾期的数据
     *
     * @param searchVo    电商会员逾期或挂单的搜索vo
     * @param dto         当前电商会员
     * @param executeDate 当前的发生日期
     */
    private void doGenerateRenewComExpiry(CommonsSearchVo searchVo, ComDto dto, DateTime executeDate) {
        // 统计当天有没有逾期
        // 获取所有续期的原始仓单
        Collection<PledgeDto> origPledgeList = pledgeMapper.selectRenew(searchVo);
        if (CollectionUtils.isNotEmpty(origPledgeList)) {
            for (PledgeDto origPledge : origPledgeList) {
                PledgeDto childRenewPledge = pledgeMapper.getMaxRenewPledgeDto(origPledge.getId());
                if (Objects.nonNull(childRenewPledge)) {
                    if (getRenewExpiryCount(searchVo, dto, origPledge, childRenewPledge, executeDate)) return;
                }
            }
        }

        // 判断当前日期没有逾期或者挂单的统计数
        if (checkIsExits(searchVo, executeDate)) return;
        saveRenewComExpiry(searchVo, dto, executeDate, 0, 0);
    }

    /**
     * 没有做过续期的初始仓单
     *
     * @param searchVo
     * @param dto
     * @param executeDate
     * @return
     */
    private boolean doNoneRenewCheckAndSave(CommonsSearchVo searchVo, ComDto dto, DateTime executeDate) {
        if (checkIsExits(searchVo, executeDate)) return Boolean.TRUE;
        saveRenewComExpiry(searchVo, dto, executeDate, NumberUtils.INTEGER_ONE, NumberUtils.INTEGER_ZERO);
        return Boolean.TRUE;
    }

    /**
     * 统计总的逾期与挂单天数和一年的逾期与挂单天数
     *
     * @param isTotal
     * @param searchVo
     * @param comExpiry
     */
    private void wrapperTotalOrYearDays(boolean isTotal, CommonsSearchVo searchVo, ComExpiryDto comExpiry) {
        StatisticsComDto comDto = comExpiryMapper.getDays(searchVo);
        if (Objects.nonNull(comDto)) {
            // 之前的加上当前新增的
            int expiry = BigDecimal.valueOf(comDto.getExpiry())
                    .add(BigDecimal.valueOf(comExpiry.getExpiry()))
                    .intValue();

            int quotes = BigDecimal.valueOf(comDto.getQuotes())
                    .add(BigDecimal.valueOf(comExpiry.getQuotes()))
                    .intValue();
            if (isTotal) {
                comExpiry.setTotalExpiry(expiry);
                comExpiry.setTotalQuotes(quotes);
            } else {
                comExpiry.setYearExpiry(expiry);
                comExpiry.setYearQuotes(quotes);
            }
        } else {
            // 初始化的数据
            comExpiry.setTotalExpiry(comExpiry.getExpiry());
            comExpiry.setTotalQuotes(comExpiry.getQuotes());
            comExpiry.setYearExpiry(comExpiry.getExpiry());
            comExpiry.setYearQuotes(comExpiry.getQuotes());
        }
    }

    /**
     * 生成电商贸易会员逾期统计报表
     *
     * @param searchVo
     * @param dto
     * @param initExpiry  逾期的初始值
     * @param initQuotes  挂单的初始值
     * @param executeDate
     * @param years
     * @return
     */
    private ComExpiryDto createComExpiryDto(CommonsSearchVo searchVo, ComDto dto,
                                            int initExpiry, int initQuotes,
                                            DateTime executeDate, Date years) {
        ComExpiryDto expiry = new ComExpiryDto();
        expiry.setUcId(dto.getUcId());
        expiry.setExpiry(initExpiry);
        expiry.setQuotes(initQuotes);
        expiry.setCreateDate(executeDate.millisOfDay().withMinimumValue().toDate());
        expiry.setModifyDate(executeDate.millisOfDay().withMinimumValue().toDate());

        // 统计总的逾期统计
        searchVo.setBeginDate(null);
        searchVo.setEndDate(null);
        wrapperTotalOrYearDays(Boolean.TRUE, searchVo, expiry);

        // 统计一年的逾期统计
        searchVo.setBeginDate(years);
        searchVo.setEndDate(executeDate.millisOfDay().withMaximumValue().toDate());
        wrapperTotalOrYearDays(Boolean.FALSE, searchVo, expiry);
        return expiry;
    }

    private boolean saveRenewComExpiry(CommonsSearchVo searchVo, ComDto dto, DateTime currentDate,
                                       int initExpiry, int initQuotes) {
        Date years = DateUtils.addYears(currentDate.toDate(), -1);
        ComExpiryDto expiryDto = createComExpiryDto(searchVo, dto, initExpiry, initQuotes, currentDate, years);
        return comExpiryMapper.save(expiryDto) > 0 ? Boolean.TRUE : Boolean.FALSE;
    }

    /**
     * 判断当前日期的数据是否存在
     *
     * @param searchVo
     * @param currentDate
     * @return
     */
    private boolean checkIsExits(CommonsSearchVo searchVo, DateTime currentDate) {
        searchVo.setBeginDate(currentDate.millisOfDay().withMinimumValue().toDate());
        searchVo.setEndDate(currentDate.millisOfDay().withMaximumValue().toDate());
        long count = comExpiryMapper.count(searchVo);
        if (count > 0) return Boolean.TRUE;
        return Boolean.FALSE;
    }
}